package xyz.fivefaith.cloud.common.mybatis.config;

import cn.hutool.core.net.NetUtil;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import xyz.fivefaith.cloud.common.mybatis.aspect.DataPermissionAspect;
import xyz.fivefaith.cloud.common.mybatis.handler.InjectionMetaObjectHandler;
import xyz.fivefaith.cloud.common.mybatis.handler.MybatisExceptionHandler;
import xyz.fivefaith.cloud.common.mybatis.handler.PlusPostInitTableInfoHandler;
import xyz.fivefaith.cloud.common.mybatis.interceptor.PlusDataPermissionInterceptor;
import xyz.fivefaith.cloud.common.mybatis.service.SysDataScopeService;
import xyz.fivefaith.tool.boot.factory.YmlPropertySourceFactory;
import xyz.fivefaith.tool.boot.util.SpringUtil;

/**
 * mybatis-plus配置类(下方注释有插件介绍)
 *
 * @author Lion Li
 */
@AutoConfiguration
@EnableTransactionManagement(proxyTargetClass = true)
@MapperScan("${mybatis-plus.mapperPackage}")
@PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class)
public class MybatisPlusConfiguration {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 多租户插件 必须放到第一位
        try {
            TenantLineInnerInterceptor tenant =
                    SpringUtil.getBean(TenantLineInnerInterceptor.class);
            interceptor.addInnerInterceptor(tenant);
        } catch (BeansException ignore) {
        }
        // 数据权限处理
        interceptor.addInnerInterceptor(dataPermissionInterceptor());
        // 分页插件
        interceptor.addInnerInterceptor(paginationInnerInterceptor());
        // 乐观锁插件
        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
        return interceptor;
    }

    /** 数据权限拦截器 */
    public PlusDataPermissionInterceptor dataPermissionInterceptor() {
        return new PlusDataPermissionInterceptor(
                SpringUtil.getProperty("mybatis-plus.mapperPackage"));
    }

    /** 数据权限切面处理器 */
    @Bean
    public DataPermissionAspect dataPermissionAspect() {
        return new DataPermissionAspect();
    }

    /** 分页插件，自动识别数据库类型 */
    public PaginationInnerInterceptor paginationInnerInterceptor() {
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        // 分页合理化
        paginationInnerInterceptor.setOverflow(true);
        return paginationInnerInterceptor;
    }

    /** 乐观锁插件 */
    public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
        return new OptimisticLockerInnerInterceptor();
    }

    /** 元对象字段填充控制器 */
    @Bean
    public MetaObjectHandler metaObjectHandler() {
        return new InjectionMetaObjectHandler();
    }

    /** 使用网卡信息绑定雪花生成器 防止集群雪花ID重复 */
    @Bean
    public IdentifierGenerator idGenerator() {
        return new DefaultIdentifierGenerator(NetUtil.getLocalhost());
    }

    /** 异常处理器 */
    @Bean
    public MybatisExceptionHandler mybatisExceptionHandler() {
        return new MybatisExceptionHandler();
    }

    /** 数据权限处理实现 */
    @Bean("sdss")
    public SysDataScopeService sysDataScopeService() {
        return new SysDataScopeService();
    }

    /** 初始化表对象处理器 */
    @Bean
    public PostInitTableInfoHandler postInitTableInfoHandler() {
        return new PlusPostInitTableInfoHandler();
    }

    /**
     * PaginationInnerInterceptor 分页插件，自动识别数据库类型 https://baomidou.com/pages/97710a/
     * OptimisticLockerInnerInterceptor 乐观锁插件 https://baomidou.com/pages/0d93c0/ MetaObjectHandler
     * 元对象字段填充控制器 https://baomidou.com/pages/4c6bcf/ ISqlInjector sql注入器
     * https://baomidou.com/pages/42ea4a/ BlockAttackInnerInterceptor 如果是对全表的删除或更新操作，就会终止该操作
     * https://baomidou.com/pages/f9a237/ IllegalSQLInnerInterceptor sql性能规范插件(垃圾SQL拦截)
     * IdentifierGenerator 自定义主键策略 https://baomidou.com/pages/568eb2/ TenantLineInnerInterceptor
     * 多租户插件 https://baomidou.com/pages/aef2f2/ DynamicTableNameInnerInterceptor 动态表名插件
     * https://baomidou.com/pages/2a45ff/
     */
}
